package com.dongnao.network.nio_hashcat;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.SelectableChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author sjy
 * @date 2024年05月12日 16:59
 */
public class ServerBootstrap {
    //处理客户端的连接
    private ReactorThread mainReactor;
    //处理客户端的IO请求
    private ReactorThread[] subReactors = new ReactorThread[Runtime.getRuntime().availableProcessors()];
    //主线程的事件处理器
    private ChannelHandler handler;
    //子线程的事件处理器
    private ChannelHandler childHandler;

    //业务操作的线程
    private static ExecutorService workPool = Executors.newCachedThreadPool();

    public ServerBootstrap mainHandler(ChannelHandler h) {
        handler = h;
        return this;
    }

    public ServerBootstrap childHandler(ChannelHandler h) {
        childHandler = h;
        return this;
    }

    public ServerBootstrap() throws IOException {
        handler = childHandler = new ChannelHandlerAdapter();
        for (int i = 0; i < subReactors.length; i++) {
            subReactors[i] = new ReactorThread() {
                @Override
                void dispatch(SelectableChannel channel) {
                    workPool.execute(() -> {
                        try {
                            childHandler.channelRead(channel);
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    });
                }
            };
        }
        mainReactor = new ReactorThread() {
            AtomicInteger incr = new AtomicInteger(0);

            @Override
            void dispatch(SelectableChannel channel) {
                try {
                    ServerSocketChannel ch = (ServerSocketChannel) channel;
                    SocketChannel socketChannel = ch.accept();
                    socketChannel.configureBlocking(false);
                    //收到连接建立的通知后，分发给IO线程继续读取数据
                    int index = incr.getAndIncrement() % subReactors.length;
                    ReactorThread workEventLoop = subReactors[index];
                    workEventLoop.doStart();
                    SelectionKey selectionKey = workEventLoop.register(socketChannel);
                    selectionKey.interestOps(SelectionKey.OP_READ);
                    System.out.println(Thread.currentThread().getName() + " 收到新连接：" + socketChannel);
                } catch (IOException e) {
                    e.printStackTrace();
                    try {
                        channel.close();
                    } catch (IOException e1) {
                        e1.printStackTrace();
                    }
                }
            }
        };
    }

    public void bind(int port) throws IOException {
        ServerSocketChannel channel = init();
        channel.bind(new InetSocketAddress(port));
        System.out.println("----服务端启动了----");
    }

    private ServerSocketChannel init() throws IOException {
        ServerSocketChannel channel = ServerSocketChannel.open();
        channel.configureBlocking(false);
        mainReactor.doStart();
        SelectionKey key = mainReactor.register(channel);
        key.interestOps(SelectionKey.OP_ACCEPT);
        handler.channelRegistered(channel);
        return channel;
    }


    public static void main(String[] args) {
        try {
            ServerBootstrap bootstrap = new ServerBootstrap();
            bootstrap.mainHandler(new ChannelHandlerAdapter() {
                @Override
                public void channelRegistered(SelectableChannel channel) {
                    System.out.println("服务已注册：" + channel);
                }
            }).childHandler(new RequestHandler());
            bootstrap.bind(8080);
//            LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(5));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
